package service

import (
	"context"
	"fmt"

	"github.com/pkg/errors"

	"bmember/internal/dao"
	"bmember/internal/model"

	pb "bmember/api/pb/server"
	"bmember/pkg/lueerror"
)

type cardSrv struct {
	*Service
	name string
}

var cSrv *cardSrv

// InitCardSrv  初始化体系相关逻辑层定义
func InitCardSrv() {
	cSrv = &cardSrv{
		Service: service,
		name:    "group_service",
	}
}

// GetCardSrv 获得体系相关逻辑层定义
func GetCardSrv() *cardSrv {
	return cSrv
}

func (srv *cardSrv) toCardInfoReply(card *model.AccountCard) *pb.CardInfoReply {
	if card == nil {
		return nil
	}
	return &pb.CardInfoReply{
		CardId:             card.Id,
		BrandId:            card.BrandId,
		GroupId:            card.GroupId,
		Name:               card.Name,
		CardType:           card.GetCardType(),
		Discount:           card.GetDiscount(),
		IsDefault:          card.IsDefault,
		CanIntegral:        card.CanIntegral,
		UnitIntegralAmount: card.GetUnitIntegralAmount(),
		CanRecharge:        card.CanRecharge,
		TopupLimit:         card.GetTopupLimit(),
		Cover:              card.Cover,
		Deposit:            card.Deposit,
	}
}

// 目前来说，每个品牌只有一个体系
func (srv *cardSrv) getBrandGroup(ctx context.Context, brandId int64) (*model.AccountGroup, lueerror.LueError) {
	groups, err := dao.GetCardDao().GetAccountGroupByBrandId(ctx, brandId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if len(groups) == 0 {
		return nil, nil
	}
	return groups[0], nil
}

// CreatAccountCard 创建会员卡
func (srv *cardSrv) CreatAccountCard(ctx context.Context, brandId int64, p *pb.CreateCardReq, empId int64) (*pb.CardInfoReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	// 获取品牌唯一体系
	group, errL := srv.getBrandGroup(ctx, brandId)
	if errL != nil {
		return nil, errL
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		// 体系不存在，创建一个体系
		var err error
		isFirst := group == nil
		if isFirst {
			group = model.NewAccountGroup(brandId, "", empId)
			group.Id, err = dao.GetCardDao().CreateAccountGroup(ctx, group)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		card := model.NewAccountCard(brandId, group.Id, model.GetInnerCardType(p.CardType), p.Name, p.Cover, empId)
		// 充值设置
		if p.CanRecharge {
			if p.TopupLimit < 1 {
				return nil, lueerror.InvalidCardConfig(errors.New("起充金额需大于1分"))
			}
			card.SetTopupLimit(p.TopupLimit)
		}
		// 积分设置
		if p.CanIntegral {
			if p.UnitIntegralAmount < 1 {
				return nil, lueerror.InvalidCardConfig(errors.New("单价积分金额需大于1"))
			}
			card.SetIntegralRule(p.UnitIntegralAmount)
		}
		// 第一张卡为默认卡
		if isFirst {
			card.SetAsDefault()
		}
		// 折扣设置
		card.SetDiscount(p.Discount)
		// 第一张卡设置为默认卡
		card.Id, err = dao.GetCardDao().CreateAccountCard(ctx, card)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return card, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	return srv.toCardInfoReply(ret.(*model.AccountCard)), nil
}

// UpdateAccountCard 更新卡类型
func (srv *cardSrv) UpdateAccountCard(ctx context.Context, brandId int64, p *pb.UpdateCardReq, editorId int64) (*pb.CardInfoReply, lueerror.LueError) {
	if p == nil {
		return nil, nil
	}
	ret, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		card, err := dao.GetCardDao().LockAccountCardById(ctx, p.CardId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if card == nil || card.BrandId != brandId {
			return nil, lueerror.CardNotExist(fmt.Errorf("卡 %d 不存在", p.CardId))
		}
		card.Update(p.Name, p.Cover, editorId)
		// 充值设置
		if p.CanRecharge {
			if p.TopupLimit < 1 {
				return nil, lueerror.InvalidCardConfig(errors.New("起充金额需大于1分"))
			}
			card.SetTopupLimit(p.TopupLimit)
		}
		// 积分设置
		if p.CanIntegral {
			if p.UnitIntegralAmount < 1 {
				return nil, lueerror.InvalidCardConfig(errors.New("单价积分金额需大于1"))
			}
			card.SetIntegralRule(p.UnitIntegralAmount)
		}
		// 折扣设置
		card.SetDiscount(p.Discount)
		err = dao.GetCardDao().UpdateAccountCard(ctx, card)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return card, nil
	})
	if err != nil {
		return nil, parseLueerror(err)
	}
	return srv.toCardInfoReply(ret.(*model.AccountCard)), nil
}

// GetAccountCardList 获取卡定义列表
func (srv *cardSrv) GetAccountCardList(ctx context.Context, brandId int64) (*pb.CardListReply, lueerror.LueError) {
	group, errL := srv.getBrandGroup(ctx, brandId)
	if errL != nil {
		return nil, errL
	}
	if group == nil {
		return &pb.CardListReply{
			Cards: []*pb.CardInfoReply{},
		}, nil
	}
	cards, err := dao.GetCardDao().GetAccountCardsByGroup(ctx, brandId, group.Id)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	rCards := make([]*pb.CardInfoReply, len(cards))
	for idx, c := range cards {
		rCards[idx] = srv.toCardInfoReply(c)
	}
	return &pb.CardListReply{Cards: rCards}, nil
}

// GetCardById 获取卡详情
func (srv *cardSrv) GetCardById(ctx context.Context, brandId, cardId int64) (*pb.CardInfoReply, lueerror.LueError) {
	card, err := dao.GetCardDao().GetAccountCardById(ctx, cardId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if card == nil || card.BrandId != brandId {
		return nil, lueerror.CardNotExist(fmt.Errorf("品牌 %d 不存在卡 %d", brandId, cardId))
	}
	return srv.toCardInfoReply(card), nil
}

// SetCardDefaultStatus 设置卡默认状态
func (srv *cardSrv) SetCardDefaultStatus(ctx context.Context, brandId, cardId int64, isDefault bool, editorId int64) lueerror.LueError {
	_, err := dao.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		card, err := dao.GetCardDao().LockAccountCardById(ctx, cardId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		if card == nil || card.BrandId != brandId {
			return nil, lueerror.CardNotExist(fmt.Errorf("卡 %d 不存在", cardId))
		}
		// 状态不变
		if card.IsDefault == isDefault {
			return nil, nil
		}
		// 设置为默认卡,先关闭该体系下其他默认卡
		if isDefault {
			err = dao.GetCardDao().DisableDefaultCard(ctx, brandId, card.GroupId, editorId)
			if err != nil {
				return nil, lueerror.DbErr(err)
			}
		}
		// 设置卡的默认卡状态
		err = dao.GetCardDao().SetDefaultCard(ctx, card.Id, isDefault, editorId)
		if err != nil {
			return nil, lueerror.DbErr(err)
		}
		return nil, nil
	})
	return parseLueerror(err)
}

// GetCardNames 返回卡名列表
func (srv *cardSrv) GetCardNames(ctx context.Context, brandId int64) (*pb.CardNameListReply, lueerror.LueError) {
	cards, err := dao.GetCardDao().GetAccountCardsNameByBrand(ctx, brandId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	rCards := make([]*pb.CardName, len(cards))
	for idx, c := range cards {
		rCards[idx] = &pb.CardName{
			CardId:   c.Id,
			CardName: c.Name,
		}
	}
	return &pb.CardNameListReply{Cards: rCards}, nil
}

// BrandHasCards 判断品牌是否有卡
func (srv *cardSrv) BrandHasCards(ctx context.Context, brandId int64) (bool, lueerror.LueError) {
	cards, err := dao.GetCardDao().GetAccountCardsNameByBrand(ctx, brandId)
	if err != nil {
		return false, lueerror.DbErr(err)
	}
	return len(cards) > 0, nil
}
